package com.qiangzi.workflow.engine.bpmn.task;

import java.util.concurrent.ConcurrentHashMap;

import org.dom4j.Attribute;
import org.dom4j.Element;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;

import com.qiangzi.workflow.engine.bpmn.base.ProcessInstance;
import com.qiangzi.workflow.engine.bpmn.delegate.DelegateExecution;
import com.qiangzi.workflow.engine.bpmn.delegate.ExecutionContext;
import com.qiangzi.workflow.engine.bpmn.delegate.JavaDelegate;

public class ServiceTask extends Task {

	// 整个JVM共用的部分
	// 可能涉及到类的加载/卸载
	private static final ConcurrentHashMap<String, Object> CACHED_JAVA_DELEGATE = new ConcurrentHashMap<String, Object>();
	private static final Object LOCK = new Object();

	private String className;

	public String getClassName() {
		return className;
	}

	@SuppressWarnings("rawtypes")
	public void parse(Element element) throws Exception {

		super.parse(element);

		Assert.isTrue(null != element, "element is null");

		// 提取class的值
		Attribute classAttribute = element.attribute("class");
		Assert.isTrue(null != classAttribute, "class attribute must exist in Task");
		String className = classAttribute.getText();
		Assert.hasText(className, "class attribute not valid in Task");
		// 确保是JavaDelegate类
		Class businessClass = Class.forName(className);
		Assert.isAssignable(JavaDelegate.class, businessClass,
				"wrong class,It must be implementation of interface JavaDelegate - " + className);
		this.className = className;

	}

	public void deploy() {
		super.deploy();
	}

	/**
	 * 覆盖
	 * 
	 * @throws Exception
	 */
	@Override
	public void invoke(ProcessInstance instance, ApplicationContext applicationContext) throws Exception {

		// action部分
		Object cachedObject = CACHED_JAVA_DELEGATE.get(className);
		if (null == cachedObject) {
			synchronized (LOCK) {
				cachedObject = CACHED_JAVA_DELEGATE.get(className);
				if (null == cachedObject) {
					cachedObject = applicationContext.getBean(Class.forName(className));
					CACHED_JAVA_DELEGATE.put(className, cachedObject);
				}
			}
		}
		// 从spring context中获取bean
		// 因为可能涉及到类的加载/卸载
		// Object cachedObject = applicationContext.getBean(Class.forName(className));
		Assert.isTrue(null != cachedObject, "fail to get bean obj for " + className);
		Assert.isTrue(cachedObject instanceof JavaDelegate, "bean obj must be JavaDelegate type for " + className);
		JavaDelegate delegate = (JavaDelegate) cachedObject;
		DelegateExecution executionContext = new ExecutionContext(instance);
		delegate.execute(executionContext);

		// 这里直接调用node的invoke函数
		// 因为针对ServiceTask来说-其它都是类似的操作,没有特别的语义
		// 所以直接复用了父类的逻辑
		super.invoke(instance, applicationContext);

	}

}